package com.htfyun.factorytest.agingtest;

import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.wifi.WifiManager;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemProperties;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;

import com.blankj.utilcode.util.VolumeUtils;
import com.htfyun.factorytest.R;
import com.htfyun.factorytest.RootApplication;
import com.htfyun.factorytest.common.BatteryCurrentThresholdEnum;
import com.htfyun.factorytest.common.BatteryInfo;
import com.htfyun.factorytest.common.Constants;
import com.htfyun.factorytest.common.FTUtils;
import com.htfyun.factorytest.common.ForeLightCtrl;
import com.htfyun.factorytest.config.EinkProperty;
import com.htfyun.factorytest.device.DeviceAttr;
import com.htfyun.factorytest.factorytestui.FactoryTestItemsEnum;
import com.htfyun.factorytest.myrecorder.IRecordListener;
import com.htfyun.factorytest.myrecorder.RecorderOperator;
import com.htfyun.factorytest.utils.DebugLog;
import com.htfyun.factorytest.utils.FileReadWrite;
import com.htfyun.factorytest.utils.MemTester;
import com.htfyun.factorytest.utils.TimeStringUtils;
import com.htfyun.factorytest.utils.UsefulUtils;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class TestHardware extends AgingTestItemBase {

    private final boolean ENABLE_UPDATE_SCREEN = EinkProperty.isAgingScreen();

    private static final int MSG_TEST_SCREEN = 10;
    private static final int PERIOD_TEST_SCREEN = EinkProperty.isDualScreen() ? 1600 : 800;

    private static final int MSG_TOGGLE_WIFI = 20;
    private static final int PERIOD_TOGGLE_WIFI = UsefulUtils.isLowRamDevice() ? 12000 : 8000;
    private static final int PERIOD_DISABLE_WIFI = UsefulUtils.isLowRamDevice() ? 6000 : 3000;

    private static final int MSG_TOGGLE_BT = 30;
    private static final int PERIOD_TOGGLE_BT = UsefulUtils.isLowRamDevice() ? 6000 : 4000;

    private static final int MSG_RECORD_START = 40;
    private static final int PERIOD_RECORD_START = 60 * 1000;
    private static final int PERIOD_DELAY_START = 3 * 1000;

    private static final int MSG_RECORD_STOP = 41;
    private static final int PERIOD_RECORD_STOP = 5 * 1000;

    private static final int MSG_PLAY_SOUND_START = 50;
    private static final int MSG_PLAY_SOUND_STOP = 51;
    private static final int PERIOD_PALY_SOUND_STOP = 5 * 1000;

    private static final int MSG_CHECK_TEST_CPU = 60;
    private static final int PERIOD_CHECK_TEST_CPU = 1000 * 60 * 4;// 4min

    private static final int MSG_ENABLE_MODEL = 70;
    private static final int MSG_DISABLE_MODEL = 71;
    private static final int PERIOD_TOGGLE_MODEL = 1000 * 10;
    private final Random mRandom = new Random();
    private final WifiManager wm;

    public TestHardware(@NonNull Context context, @NonNull View view) {
        super(context, view);
        wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
    }

    @Override
    protected void handleMessage(Message msg) {
        final int what = msg.what;
        final boolean isEnabled = msg.arg1 == 1;
        switch (what) {
            case MSG_TEST_SCREEN:
                updateScreen();
                //更新 screen 的时候, 更新状态数据显示
                updateHardwareAgingInfo();
                break;
            case MSG_TOGGLE_WIFI:
//                toggleWifiEnable();
                if (isEnabled == wm.isWifiEnabled()) {
                    DebugLog.d("wifi error +1");
                    int count = AgingTestItemAttr.getHardwareWifiErrorCount(getContext());
                    count++;
                    AgingTestItemAttr.setHardwareWifiErrorCount(getContext(), count);

//                    toggleWifiEnable(!isEnabled);
//                    int delay = isEnabled ? PERIOD_DISABLE_WIFI : PERIOD_TOGGLE_WIFI;
//                    DebugLog.d("Delay " + delay + "ms to control wifi " + isEnabled);
//                    sendMessageDelay(MSG_TOGGLE_WIFI, isEnabled, delay);
//                    stopFlag = true;
                } /*else {
                    toggleWifiEnable(isEnabled);
                    int delay = isEnabled ? PERIOD_TOGGLE_WIFI : PERIOD_DISABLE_WIFI;
                    DebugLog.d("Delay " + delay + "ms to control wifi " + !isEnabled);
                    sendMessageDelay(MSG_TOGGLE_WIFI, !isEnabled, delay);
                }*/
                toggleWifiEnable(isEnabled);
                int delay = isEnabled ? PERIOD_TOGGLE_WIFI : PERIOD_DISABLE_WIFI;
                DebugLog.d("Delay " + delay + "ms to control wifi " + !isEnabled);
                sendMessageDelay(MSG_TOGGLE_WIFI, !isEnabled, delay);
                break;
            case MSG_TOGGLE_BT:
                toggleBluetoothEnable();
                break;
            case MSG_RECORD_START:
                startRecordTread();
                break;
            case MSG_RECORD_STOP:
                stopRecordThread();
                break;
            case MSG_PLAY_SOUND_START:
                doStartTestPlaySound();
                break;
            case MSG_PLAY_SOUND_STOP:
                stopTestPlaySound();
                break;
            case MSG_CHECK_TEST_CPU:
                checkResultOfCpuTest();
                break;
            case MSG_ENABLE_MODEL:
                enableLteModel();
                break;
            case MSG_DISABLE_MODEL:
                disableLteModel();
                break;

        }
    }

    private void sendMessageDelay(int what, boolean b, int delay) {
        Message m = new Message();
        m.what = what;
        m.arg1 = b ? 1 : 0;
        getHandler().sendMessageDelayed(m, delay);
    }

    @Override
    protected void doStartTest() {

        DebugLog.e("TestHardware doStartTest");

//        startTestMemory();

        startTestScreen();

//        startTestRecord();

        if (DeviceAttr.getRunningDeviceAttr().hasBluetooth()) {
            startTestBT();
        }
        if (DeviceAttr.getRunningDeviceAttr().hasWiFi()) {
            startTestWifi();
        }

        startTestPlaySound();

        startBatteryInfo();

        /*if (!UsefulUtils.isLowRamDevice())*/
        startTestEmmc();

        startCpuTest();

        acquireWakeLock();

        if (RootApplication.enableUsbCheck) {
            startTestLteModel();
        }
    }

    @Override
    protected void doStopTest() {
        DebugLog.e("TestHardware doStopTest");

        if (getLinearLayoutContainer() != null) {
            getLinearLayoutContainer().setBackgroundColor(Color.TRANSPARENT);
        }
//        stopTestMemory();

        if (DeviceAttr.getRunningDeviceAttr().hasBluetooth()) {
            stopTestBT();
        }
        if (DeviceAttr.getRunningDeviceAttr().hasWiFi()) {
            stopTestWifi();
        }

        stopTestScreen();

        stopTestPlaySound();

        stopBatteryInfo();

//        stopTestRecord();

        /*if (UsefulUtils.isLowRamDevice())*/
        stopTestEmmc();

        stopCpuTest();

        releaseWakeLock();

        stopTestLteModel();

        //reset mute prop
        SystemProperties.set(Constants.FT_AGING_MUTE, "false");
    }

    @Override
    public AgingTestItemAttr getAgingTestItemAttr() {
        return AgingTestItemAttr.hardware;
    }

    private boolean ledOn = false;

    private void updateHardwareAgingInfo() {

        String screenState = getContext().getString(R.string.aging_hardware_screen,
                AgingTestItemAttr.getHardwareScreenCount(getContext()));

        String playSoundState = "";
        if (mediaPlayer != null) {
            int duration = mediaPlayer.getDuration();
            int pos = mediaPlayer.getCurrentPosition();
            String durationStr = TimeStringUtils.makeTimeString(duration);
            String posStr = TimeStringUtils.makeTimeString(pos);

            int count = AgingTestItemAttr.getHardwarePlaySoundCount(getContext());
            playSoundState = getContext().getString(R.string.aging_hardware_play_sound, count, durationStr, posStr);

        }

        final long usedTime = AgingTestItemAttr.getAgingTimeTick_ms(getContext()) - getAgingTestItemAttr().getStartTime_ms(getContext());
        final String timeStr = TimeStringUtils.makeTimeString(usedTime);

        String hardwareAgingTimeString = getContext().getString(R.string.aging_hardware_time_used, timeStr);

/*        int recordCnt = AgingTestItemAttr.getHardwareRecordCount(getContext());
        String recordState = getContext().getString(R.string.aging_hardware_record, recordCnt);*/

        int ledCnt = AgingTestItemAttr.getHardwareLedCount(getContext());
        ledOn = !ledOn;
        if (ledOn) {
            ledCnt++;
            AgingTestItemAttr.setHardwareLedCount(getContext(), ledCnt);
        }
//        LedCtrl.setLed(ledOn, LedCtrl.LedAttr.led_green);
//        LedCtrl.setLed(!ledOn, LedCtrl.LedAttr.led_red);


        String ledState = getContext().getString(R.string.aging_hardware_led, ledCnt);

        if (DeviceAttr.getRunningDeviceAttr().hasForeLight()) {
//            ForeLightCtrl.getForeLightCtrl().setColdLightBrightness(getContext(), ledOn ? ForeLightCtrl.MAX_BRIGHTNESS : 0);
//            ForeLightCtrl.getForeLightCtrl().setWarmLightBrightness(getContext(), !ledOn ? ForeLightCtrl.MAX_BRIGHTNESS : 0);
            if (ledOn) {
                if (0 == (ledCnt % 2)) {
                    ForeLightCtrl.setColdBrightMax(getContext());
                } else if (1 == (ledCnt % 2)) {
                    ForeLightCtrl.setWarmBrightMax(getContext());
                }
            } else ForeLightCtrl.setBrightMin(getContext());
        }

        int cpuTestCount = AgingTestItemAttr.getHardwareCpuTestCount(getContext());
        int cpuTestFailCount = AgingTestItemAttr.getHardwareCpuFailCount(getContext());

        String cpuState = getContext().getString(R.string.aging_hardware_cpu_test, cpuTestCount, cpuTestFailCount, EinkProperty.getResultCpuTest());

//        String errorBootState = getContext().getString(R.string.aging_hardware_error_boot, EinkProperty.getErrorBootCount());

        String emmcState = getContext().getString(R.string.aging_hardware_emmc_test, AgingTestItemAttr.getHardwareEmmcCount(getContext()));

        String allInfo = screenState + playSoundState /*+ recordState*/
                + mBTState + mWifiState + mLteModelState + mBatteryState + ledState
                + cpuState /*+ errorBootState*/ + emmcState
                + hardwareAgingTimeString;

        updateTxtItemInfo(allInfo);

    }

    ////////////////////////
    // Lte model power on and off test
    ////////////////////////
    private static final String MODEL_STATUS_PATH = "/sys/class/rk_modem/modem_status";
    private final File ttyUSB0 = new File("/dev/ttyUSB1");
    private String mLteModelState = "";
    //    private UsbFileObserver usbFileObserver;
//    private int errorTimes = 0, toggleTimes = 0;

    private void startTestLteModel() {
        DebugLog.d("startTestLteModel");
//        usbFileObserver = new UsbFileObserver(getHandler(), MODEL_DIR);
//        usbFileObserver.startWatching();
//        if (ttyUSB0.exists()) {
        getHandler().sendEmptyMessageDelayed(ttyUSB0.exists() ? MSG_DISABLE_MODEL : MSG_ENABLE_MODEL, 3000);
//        } else {
//            getHandler().sendEmptyMessageDelayed(MSG_ENABLE_MODEL, 3000);
//        }

    }

    private void stopTestLteModel() {
        enableLteModel();
        getHandler().removeMessages(MSG_ENABLE_MODEL);
        getHandler().removeMessages(MSG_DISABLE_MODEL);
    }

    private void enableLteModel() {
        FileReadWrite.writeStringToFile(MODEL_STATUS_PATH, "1");
//        DebugLog.d("11111 modem_status = " + FileReadWrite.readFileByLines(MODEL_STATUS_PATH));
        getHandler().sendEmptyMessageDelayed(MSG_DISABLE_MODEL, PERIOD_TOGGLE_MODEL);

    }

    private void disableLteModel() {
        int toggleTimes = AgingTestItemAttr.getHardwareLteModelOnOffCount(getContext());
        int errorTimes = AgingTestItemAttr.getHardwareLteModelOnOffErrorCount(getContext());
//        DebugLog.d("toggleTimes = " + toggleTimes + ", errorTimes = " + errorTimes);
        if (!ttyUSB0.exists()) {
            errorTimes++;
//            getAgingTestItemAttr().setForceTestOver(getContext(), true);
        }
        AgingTestItemAttr.setHardwareLteModelOnOffCount(getContext(), ++toggleTimes);
        AgingTestItemAttr.setHardwareLteModelOnOffErrorCount(getContext(), errorTimes);
        mLteModelState = getContext().getString(R.string.aging_hardware_lte_model_state, toggleTimes, errorTimes);

//        DebugLog.d("toggle times = " + toggleTimes++ + ", error times = " + errorTimes);
        FileReadWrite.writeStringToFile(MODEL_STATUS_PATH, "0");
//        DebugLog.d("11111 modem_status = " + FileReadWrite.readFileByLines(MODEL_STATUS_PATH));
        getHandler().sendEmptyMessageDelayed(MSG_ENABLE_MODEL, PERIOD_TOGGLE_MODEL);

    }

    ////////////////////////
    // WakeLock
    ////////////////////////

    private PowerManager.WakeLock mWakeLock;

    private void acquireWakeLock() {
        if (mWakeLock == null) {
            PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
            if (pm == null) {
                return;
            }
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
                    this.getClass().getCanonicalName());
            mWakeLock.acquire();

        }
    }

    private void releaseWakeLock() {
        if (mWakeLock != null) {
            mWakeLock.release();
            mWakeLock = null;
        }
    }


    ////////////////////////
    // test screen
    ////////////////////////

    private int[] colorResIds;

    private int screenViewChangedCount = 0;
    private final static int SCREEN_VIEW_CHANGE_MAX_COUNT = 4;

    private void startTestScreen() {

        //拿到颜色数组
        colorResIds = getContext().getResources().getIntArray(R.array.color_gray_level);

        getHandler().sendEmptyMessage(MSG_TEST_SCREEN);

    }

    private void stopTestScreen() {
        getLinearLayoutContainer().removeAllViews();
        getHandler().removeMessages(MSG_TEST_SCREEN);

    }

    private void updateScreen() {

        if (ENABLE_UPDATE_SCREEN) {

            screenViewChangedCount++;
            if (screenViewChangedCount >= SCREEN_VIEW_CHANGE_MAX_COUNT) {
                screenViewChangedCount = 0;

                int screenTestCount = AgingTestItemAttr.getHardwareScreenCount(getContext());
                screenTestCount++;
                AgingTestItemAttr.setHardwareScreenCount(getContext(), screenTestCount);
            }

            setChildView((screenViewChangedCount & 0x1) != 0, (screenViewChangedCount & 0x2) != 0);

        }

        getHandler().sendEmptyMessageDelayed(MSG_TEST_SCREEN, PERIOD_TEST_SCREEN);

    }

    //动态加载多个view，数量为colorResIds数组中的数量
    private void setChildView(boolean colorRevert, boolean vertical) {

        if (getLinearLayoutContainer() == null) {
            return;
        }

        getLinearLayoutContainer().removeAllViews();

        getLinearLayoutContainer().setOrientation(vertical ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);

        for (int i = 0; i < colorResIds.length; i++) {
            View view = new View(getContext());
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            lp.weight = 1;
            int color = colorResIds[i];
            if (colorRevert) {
                color = colorResIds[colorResIds.length - 1 - i];
            }
            view.setBackgroundColor(color);
            view.setClickable(false);
            getLinearLayoutContainer().addView(view, lp);
        }
    }

    ////////////////////
    // play sound
    ////////////////////
    private MediaPlayer mediaPlayer;

    private void startTestPlaySound() {
        getHandler().sendEmptyMessage(MSG_PLAY_SOUND_START);
    }

    private void stopTestPlaySound() {

        getHandler().removeMessages(MSG_PLAY_SOUND_START);

        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();//回收资源
            mediaPlayer = null;
        }

//        getHandler().sendEmptyMessageDelayed(MSG_RECORD_START, PERIOD_DELAY_START);
    }

    private void doStartTestPlaySound() {
        if (mediaPlayer != null) {
            stopTestPlaySound();
        }
        try {
            boolean isMute = SystemProperties.getBoolean(Constants.FT_AGING_MUTE, false);
            DebugLog.d("doStartTestPlaySound isMute = " + isMute);
            VolumeUtils.setVolume(AudioManager.STREAM_MUSIC, isMute ? 0 : VolumeUtils.getMaxVolume(AudioManager.STREAM_MUSIC) * 22 / 30, 0);

//            mediaPlayer = MediaPlayer.create(getContext(), R.raw.music_qingzanggaoyuan);
            mediaPlayer = MediaPlayer.create(getContext(), R.raw.music_test_channel);
//            mediaPlayer.setLooping(true);//这种这个后, setOnCompletionListener 不能被调用了.
            mediaPlayer.start();

        } catch (Exception e) {
            DebugLog.e("exception e = " + e.getMessage());
        }

        mediaPlayer.setOnCompletionListener(mp -> {
            int count = AgingTestItemAttr.getHardwarePlaySoundCount(getContext());
            count++;
            AgingTestItemAttr.setHardwarePlaySoundCount(getContext(), count);

            getHandler().sendEmptyMessage(MSG_PLAY_SOUND_START);
        });

        mediaPlayer.setOnErrorListener((mp, what, extra) -> {
            DebugLog.e("onError, what = " + what + ", extra = " + extra);
            return true;
        });

//        getHandler().sendEmptyMessageDelayed(MSG_PLAY_SOUND_STOP, PERIOD_PALY_SOUND_STOP + mRandom.nextInt(5));
    }

    ///////////////////////////
    // toggle wifi
    ///////////////////////////

    private String mWifiState = "";

    private void startTestWifi() {

        registerWifiStateChangedReceiver();

//        getHandler().sendEmptyMessage(MSG_TOGGLE_WIFI);
        toggleWifiEnable(false);
        sendMessageDelay(MSG_TOGGLE_WIFI, true, PERIOD_TOGGLE_WIFI);

    }

    private void stopTestWifi() {

        unregisterWifiStateChangedReceiver();

        getHandler().removeMessages(MSG_TOGGLE_WIFI);

    }

    private void toggleWifiEnable() {
        DebugLog.i("toggleWifiEnable()");
        WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
        if (wm == null) {
            return;
        }

        wm.setWifiEnabled(!wm.isWifiEnabled());

    }

    private void toggleWifiEnable(boolean enabled) {
        DebugLog.i("toggleWifiEnable() " + enabled);
//        WifiManager wm = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
        if (wm == null) {
            return;
        }

        wm.setWifiEnabled(enabled);

    }

    private void registerWifiStateChangedReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        getContext().registerReceiver(wifiStateChangedReceiver, filter);
    }

    private void unregisterWifiStateChangedReceiver() {
        try {
            getContext().unregisterReceiver(wifiStateChangedReceiver);
        } catch (IllegalArgumentException e) {
            DebugLog.e(e.getMessage());
        }
    }

    private void updateWifiString(String state) {

        int count = AgingTestItemAttr.getHardwareWifiOnOffCount(getContext());
        int error = AgingTestItemAttr.getHardwareWifiErrorCount(getContext());
        mWifiState = getContext().getString(R.string.aging_hardware_wifi_state, state, count, error);

    }

    private BroadcastReceiver wifiStateChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (action == null) {
                return;
            }

            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {//这个监听wifi的打开与关闭，与wifi的连接无关
                int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);

                int resId = R.string.aging_hardware_status_unknown;

                switch (wifiState) {
                    case WifiManager.WIFI_STATE_DISABLED:
                        resId = R.string.aging_hardware_status_off;

//                        getHandler().sendEmptyMessageDelayed(MSG_TOGGLE_WIFI, PERIOD_TOGGLE_WIFI + mRandom.nextInt(5));
                        break;
                    case WifiManager.WIFI_STATE_DISABLING:
                        resId = R.string.aging_hardware_status_turning_off;
                        break;
                    case WifiManager.WIFI_STATE_ENABLED:
                        resId = R.string.aging_hardware_status_on;
                        int count = AgingTestItemAttr.getHardwareWifiOnOffCount(context);
                        count++;
                        AgingTestItemAttr.setHardwareWifiOnOffCount(context, count);

//                        getHandler().sendEmptyMessageDelayed(MSG_TOGGLE_WIFI, PERIOD_TOGGLE_WIFI + mRandom.nextInt(5));

                        break;
                    case WifiManager.WIFI_STATE_ENABLING:
                        resId = R.string.aging_hardware_status_turning_on;
                        break;
                    case WifiManager.WIFI_STATE_UNKNOWN:
                        DebugLog.i("wifiState:WIFI_STATE_UNKNOWN");
                        break;
                }

                updateWifiString(context.getString(resId));
            }
        }
    };

    private static final FileFilter CPU_FILTER = pathname -> {
        String path = pathname.getName();
        if (path.startsWith("cpu")) {
            for (int i = 3; i < path.length(); i++) {
                if (path.charAt(i) < '0' || path.charAt(i) > '9') {
                    return false;
                }
            }
            return true;
        }
        return false;
    };

    private boolean isRunning = true;

    private void startTestMemory() {
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                int result;
                while (isRunning) {
                    result = MemTester.memtest("8M", 2);
                    if (result != Constants.EXIT_OK) {
                        DebugLog.e("memory test fail, result = " + result);
                        stopTestMemory();
                    }
                }
            }).start();
        }
    }

    private void stopTestMemory() {
        isRunning = false;
    }

    ////////////////////////
    // toggle bt
    ////////////////////////

    private String mBTState = "";

    private void startTestBT() {

        registerBluetoothStateChangeReceiver();

        getHandler().sendEmptyMessage(MSG_TOGGLE_BT);

    }

    private void stopTestBT() {

        unregisterBluetoothStateChangeReceiver();

        getHandler().removeMessages(MSG_TOGGLE_BT);

    }

    private void toggleBluetoothEnable() {
        DebugLog.i("toggleBluetoothEnable()");
        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter == null) {
            DebugLog.e("BluetoothAdapter is null");
            return;
        }
        if (!bluetoothAdapter.isEnabled()) {
            bluetoothAdapter.enable();  //打开蓝牙，需要BLUETOOTH_ADMIN权限
        } else {
            bluetoothAdapter.disable();
        }

    }

    private void registerBluetoothStateChangeReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        getContext().registerReceiver(btStateChangedReceiver, filter);
    }

    private void unregisterBluetoothStateChangeReceiver() {
        try {
            getContext().unregisterReceiver(btStateChangedReceiver);
        } catch (IllegalArgumentException e) {
            DebugLog.e(e.getMessage());
        }
    }

    private void updateBTString(String state) {

        int count = AgingTestItemAttr.getHardwareBTOnOffCount(getContext());
        mBTState = getContext().getString(R.string.aging_hardware_bt_state, state, count);

    }

    private BroadcastReceiver btStateChangedReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            if (action == null) {
                return;
            }
            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                        BluetoothAdapter.ERROR);
                int resId = R.string.aging_hardware_status_unknown;

                switch (state) {
                    case BluetoothAdapter.STATE_OFF:
                        resId = R.string.aging_hardware_status_off;

                        getHandler().sendEmptyMessageDelayed(MSG_TOGGLE_BT, PERIOD_TOGGLE_BT + mRandom.nextInt(5));

                        break;
                    case BluetoothAdapter.STATE_TURNING_OFF:
                        resId = R.string.aging_hardware_status_turning_off;
                        break;
                    case BluetoothAdapter.STATE_ON:
                        resId = R.string.aging_hardware_status_on;

                        int count = AgingTestItemAttr.getHardwareBTOnOffCount(context);
                        count++;
                        AgingTestItemAttr.setHardwareBTOnOffCount(context, count);

                        getHandler().sendEmptyMessageDelayed(MSG_TOGGLE_BT, PERIOD_TOGGLE_BT + mRandom.nextInt(5));

                        break;
                    case BluetoothAdapter.STATE_TURNING_ON:
                        resId = R.string.aging_hardware_status_turning_on;
                        break;
                }
                updateBTString(context.getString(resId));
            }
        }
    };

    ////////////
    // battery
    ////////////

    private BatteryInfo batteryInfo;
    private String mBatteryState = "";


    private void startBatteryInfo() {

        if (batteryInfo == null) {
            batteryInfo = new BatteryInfo(getContext());
        }
        batteryInfo.setOnBatteryChangedListener(onBatteryChangedListener);
        batteryInfo.startMonitor();

    }

    private void stopBatteryInfo() {

        if (batteryInfo == null) {
            return;
        }
        batteryInfo.stopMonitor();
        batteryInfo.setOnBatteryChangedListener(null);
    }

    private BatteryInfo.OnBatteryChangedListener onBatteryChangedListener
            = info -> {

        mBatteryState = getContext().getString(R.string.aging_hardware_battery_info2,
                info.getBatteryVoltage(),
                info.getBatteryLevel(),
                info.getBatteryCapacity_mAh(),
                info.getBatteryStatusString(),
                info.getBatteryCurrent_mAh());

        BatteryCurrentThresholdEnum thresholdEnum = null;
        for (BatteryCurrentThresholdEnum e : BatteryCurrentThresholdEnum.values()) {
            if (e.isInRange(info.getBatteryLevel())) {
                thresholdEnum = e;
                break;
            }
        }

        String result = FactoryTestItemsEnum.battery.getResult(getContext());

        if (thresholdEnum != null && (info.getBatteryCurrent_mAh() >= thresholdEnum.getCurrent())) {
            result = getContext().getString(R.string.test_result_pass);
            FactoryTestItemsEnum.battery.setResult(getContext(), result);
        }

        mBatteryState = getContext().getString(R.string.ft_aging_battery_info2,
                info.getBatteryVoltage(),
                info.getBatteryLevel(),
                info.getBatteryCapacity_mAh(),
                info.getBatteryStatusString(),
                info.getBatteryCurrent_mAh(), result) + "\n";

    };

    //////////////////////////////////////////////////////////////////////////
    //test emmc

    private final static int MAX_COUNT_EMMC_TEST = 2;
    private final static int MAX_COUNT_EMMC_TEST_PRO = 1;

    private List<TestEmmcController.EmmcInfo> emmcTestWriteList = new ArrayList<>();
    private List<TestEmmcController.EmmcInfo> emmcTestReadList = new ArrayList<>();


    private void startTestEmmc() {
        TestEmmcController.getInstance().deleteTestFiles();
//        FileReadWrite.deleteFile(AgingTestItemAttr.PATH_TEST_EMMC_FAIL);

        doStartTestEmmc();
    }

    private void doStartTestEmmc() {

//        if (AgingTestItemAttr.getHardwareEmmcTestFailed(mContext)) {
//            DebugLog.e("Test emmc had failed, quit emmc test");
//            return;
//        }


        int count = AgingTestItemAttr.getHardwareEmmcCount(getContext());
        int maxCount = MAX_COUNT_EMMC_TEST;
        if (UsefulUtils.isIflytekProByCheckRom()) {
            maxCount = MAX_COUNT_EMMC_TEST_PRO;
        }

        if (count >= maxCount) {
            DebugLog.e("RockFFPlayers " + count + ", No more emmc test");
            return;
        }

        for (TestEmmcController.EmmcInfo info : TestEmmcController.EmmcInfo.values()) {
            if (!emmcTestWriteList.contains(info)) {
                emmcTestWriteList.add(info);
            }
            if (!emmcTestReadList.contains(info)) {
                emmcTestReadList.add(info);
            }
        }

        DebugLog.e("Test emmc count is " + count + ", keep emmc test");

        TestEmmcController.getInstance().addOnWROverListener(onWROverListener);
        TestEmmcController.getInstance().setMarginSpace((count) * TestEmmcController.HALF_G);
        TestEmmcController.getInstance().setContext(getContext());
        TestEmmcController.getInstance().startTest();

    }

    private void stopTestEmmc() {

        DebugLog.e("stop test emmc");

        TestEmmcController.getInstance().removeOnWROverListener(onWROverListener);
        TestEmmcController.getInstance().stopTest();

    }


    private void checkTestEmmcAndTryStartAgain() {
        if (!(emmcTestReadList.isEmpty() && emmcTestWriteList.isEmpty())) {
            return;
        }

        // 完整的测了一次.
        int count = AgingTestItemAttr.getHardwareEmmcCount(getContext());
        count++;
        DebugLog.e("checkTestEmmcAndTryStartAgain count = " + count);
        AgingTestItemAttr.setHardwareEmmcCount(getContext(), count);

        if (AgingTestItemAttr.isHardwareEmmcTestFailed(getContext())) {
            DebugLog.e("Test emmc failed, keep written file to check! Quit test emmc.");
            getAgingTestItemAttr().setForceTestOver(getContext(), true);
            return;
        }

        TestEmmcController.getInstance().stopTest();
        TestEmmcController.getInstance().deleteTestFiles();

        doStartTestEmmc();

    }

    private TestEmmcController.OnWROverListener onWROverListener =
            new TestEmmcController.OnWROverListener() {
                @Override
                public void onWriteOverListener(TestEmmcController.EmmcInfo info, long time_ms) {

                    emmcTestWriteList.remove(info);
                    checkTestEmmcAndTryStartAgain();
                }

                @Override
                public void onReadOverListener(TestEmmcController.EmmcInfo info, long time_ms) {

                    emmcTestReadList.remove(info);
                    checkTestEmmcAndTryStartAgain();

                }

                @Override
                public void onTestFailed(TestEmmcController.EmmcInfo info, String filePath, long offset, byte shouldValue, byte realValue) {

                    String log = "onTestFailed : info = " + info + ", filePath " + filePath
                            + ", offset = " + offset
                            + ", shouldValue =  0x" + Integer.toHexString((0xff & shouldValue))
                            + ", realValue = 0x" + Integer.toHexString((0xff & realValue))
                            + "\n";

                    DebugLog.e("EMMC error occurred, log path = " + AgingTestItemAttr.PATH_TEST_EMMC_HARDWARE_FAIL);

                    AgingTestItemAttr.setHardwareEmmcTestFailed(getContext(), true);

                    FileReadWrite.writeAppendFile(AgingTestItemAttr.PATH_TEST_EMMC_HARDWARE_FAIL, log);

                }
            };
    //////////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////////
    // cpu test

    private final static int MAX_COUNT_CPU_TEST = 1;


    private void startCpuTest() {

        EinkProperty.clearCpuTestResult();
        EinkProperty.clearErrorBootCount();
        doStartCpuTest();
    }

    private void doStartCpuTest() {
        EinkProperty.startOrStopCpuTest(true);

        getHandler().removeMessages(MSG_CHECK_TEST_CPU);
        getHandler().sendEmptyMessageDelayed(MSG_CHECK_TEST_CPU, PERIOD_CHECK_TEST_CPU);

    }

    private void checkResultOfCpuTest() {

        EinkProperty.CpuTestResultAttr attr = EinkProperty.getCpuTestResultAttr();
        DebugLog.e("songshitian checkResultOfCpuTest attr = " + attr);

        switch (attr) {
            case ok:
                int count = AgingTestItemAttr.getHardwareCpuTestCount(getContext());
                count++;
                AgingTestItemAttr.setHardwareCpuTestCount(getContext(), count);

                DebugLog.e("songshitian checkResultOfCpuTest ok, count = " + count);
                if (count >= MAX_COUNT_CPU_TEST) {
                    break;
                }

                doStartCpuTest();
                break;
            case fail:
                int failCount = AgingTestItemAttr.getHardwareCpuFailCount(getContext());
                failCount++;
                AgingTestItemAttr.setHardwareCpuFailCount(getContext(), failCount);

                DebugLog.e("songshitian checkResultOfCpuTest failed, count = " + failCount);
                if (failCount >= MAX_COUNT_CPU_TEST) {
                    break;
                }

                doStartCpuTest();

                break;
            default:
                getHandler().sendEmptyMessageDelayed(MSG_CHECK_TEST_CPU, PERIOD_CHECK_TEST_CPU);
                break;
        }
    }

    private void stopCpuTest() {
        getHandler().removeMessages(MSG_CHECK_TEST_CPU);
        EinkProperty.startOrStopCpuTest(false);

    }

    //////////////////////
    //    Recorder
    /////////////////////
    private RecorderThread recorderThread;

    /**
     * 要有 record 授权. 对于我们的测试的墨水屏, 他已经授权了
     */
    public void startTestRecord() {
        getHandler().removeMessages(MSG_RECORD_STOP);
        getHandler().sendEmptyMessage(MSG_RECORD_START);
    }

    private void stopTestRecord() {
        stopRecordThread();

        getHandler().removeMessages(MSG_RECORD_STOP);
        getHandler().removeMessages(MSG_RECORD_START);
    }

    private void startRecordTread() {

        if (recorderThread != null) {
            stopRecordThread();
        }

        int count = AgingTestItemAttr.getHardwareRecordCount(getContext());
        count++;
        AgingTestItemAttr.setHardwareRecordCount(getContext(), count);

        recorderThread = new RecorderThread("aging_rec-" + count, null);
        recorderThread.start();

        getHandler().sendEmptyMessageDelayed(MSG_RECORD_STOP, PERIOD_RECORD_STOP + mRandom.nextInt(5));
    }

    private void stopRecordThread() {

        if (recorderThread != null) {
            recorderThread.joinThread();
            recorderThread = null;
        }

        getHandler().sendEmptyMessageDelayed(MSG_PLAY_SOUND_START, PERIOD_DELAY_START);
//        getHandler().sendEmptyMessageDelayed(MSG_RECORD_START, PERIOD_RECORD_START);

    }

    private class RecorderThread extends Thread {

        private final String RECORDER_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "aging_recorder.pcm";


        private RecorderOperator recorderOperator;

        public RecorderThread(String name, IRecordListener listener) {
            super(name);

            recorderOperator = RecorderOperator.getInstance();
            recorderOperator.setRecordingListener(listener);
            recorderOperator.setRecordPath(RECORDER_FILE_PATH);

            if (EinkProperty.isES7210Record()) {
                recorderOperator.setChannelConfig(AudioFormat.CHANNEL_IN_STEREO);
                recorderOperator.setAudioFormat(AudioFormat.ENCODING_PCM_FLOAT);
            }

        }

        @Override
        public void run() {
            if (recorderOperator == null) {
                return;
            }

            recorderOperator.startRecord();

        }

        public void joinThread() {

            if (recorderOperator != null) {
                recorderOperator.stopRecord();
            }

            while (isAlive()) {
                try {
                    join(2500);
                } catch (InterruptedException e) {
                    // Ignore.
                }
            }
        }
    }

/*    public static class UsbFileObserver extends FileObserver {
        private AgingTestItemHandler mHandler;

        UsbFileObserver(AgingTestItemHandler handler, String path) {
            super(path, FileObserver.CREATE | FileObserver.DELETE);
            mHandler = handler;
        }

        @Override
        public void onEvent(int event, @Nullable String path) {
//            DebugLog.d("UsbFileObserver$onEvent event = " + event);
            if (!"ttyUSB1".equals(path)) {
                return;
            }
            switch (event) {
                case FileObserver.CREATE:
                    DebugLog.d("file " + path + " create");
                    mHandler.sendEmptyMessageDelayed(MSG_TOGGLE_MODEL, PERIOD_CHECK_MODEL);
                    break;

                case FileObserver.DELETE:
                    DebugLog.d("file " + path + " delete");
                    mHandler.sendEmptyMessageDelayed(MSG_TOGGLE_MODEL, PERIOD_CHECK_MODEL);
                    break;
            }
        }
    }*/
}
